package com.data.mall.service.impl;

import com.data.mall.common.KafkaTrackingDTO;
import com.data.mall.domain.Order;
import com.data.mall.domain.Sequence;
import com.data.mall.domain.StockLog;
import com.data.mall.etl.domain.enums.Event;
import com.data.mall.etl.domain.enums.Params;
import com.data.mall.exception.BusinessException;
import com.data.mall.exception.ResponseCodeEnum;
import com.data.mall.repositry.OrderRepository;
import com.data.mall.repositry.SequenceRepository;
import com.data.mall.repositry.StockLogRepository;
import com.data.mall.service.ItemService;
import com.data.mall.service.OrderService;
import com.data.mall.service.UserService;
import com.data.mall.service.dto.ItemDTO;
import com.data.mall.service.dto.OrderDTO;
import com.data.mall.service.dto.UserDTO;
import com.data.mall.utils.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author shixukai
 * @Package com.data.mall.service.impl
 * @Description: TODO
 * @date 2021/4/11
 */

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private SequenceRepository sequenceDOMapper;

    @Autowired
    private ItemService itemService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderRepository orderDOMapper;

    @Autowired
    private StockLogRepository stockLogDOMapper;

    @Override
    @Transactional
    public OrderDTO createOrder(Long userId, Long itemId, Long promoId, Integer amount, String stockLogId) throws BusinessException {
        //1.校验下单状态,下单的商品是否存在，用户是否合法，购买数量是否正确
        //ItemModel itemModel = itemService.getItemById(itemId);
        ItemDTO itemModel = itemService.getItemByIdInCache(itemId);
        if (itemModel == null) {
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }

//
        UserDTO userModel = userService.getUserByIdInCache(userId);
        if (userModel == null) {
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }
        if (amount <= 0 || amount > 99) {
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }

        //校验活动信息
        if (promoId != null) {
            //（1）校验对应活动是否存在这个适用商品
            if (promoId.intValue() != itemModel.getPromoDTO().getId()) {
                throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR, "活动信息不正确");
                //（2）校验活动是否正在进行中
            } else if (itemModel.getPromoDTO().getStatus().intValue() != 2) {
                throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR, "活动信息还未开始");
            }
        }

        //2.落单减库存
        boolean result = itemService.decreaseStock(itemId, amount);
        if (!result) {
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }

        //3.订单入库
        OrderDTO orderModel = new OrderDTO();
        orderModel.setUserId(userId);
        orderModel.setItemId(itemId);
        orderModel.setAmount(amount);
        if (promoId != null) {
            orderModel.setItemPrice(itemModel.getPromoDTO().getPromoItemPrice());
        } else {
            orderModel.setItemPrice(itemModel.getPrice());
        }
        orderModel.setPromoId(promoId);
        orderModel.setOrderPrice(new BigDecimal(orderModel.getItemPrice()).multiply(new BigDecimal(amount)).toString());

        //生成交易流水号,订单号
        orderModel.setOrderNo(generateOrderNo());
        Order orderDO = convertFromOrderModel(orderModel);
        orderDOMapper.save(orderDO);

        //加上商品的销量
        itemService.increaseSales(itemId, amount);

        //设置库存流水状态为成功
        StockLog stockLogDO = stockLogDOMapper.findByStockLogId(stockLogId);
        if (stockLogDO == null) {
            throw new BusinessException(ResponseCodeEnum.PARAMETER_VALIDATION_ERROR);
        }
        stockLogDO.setStatus(2);
        stockLogDOMapper.save(stockLogDO);
        // 埋点
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        KafkaTrackingDTO kafkaTrackingDTO = KafkaTrackingDTO.builder()
                .event(Event.USER_ORDER)
                .param(Params.ORDER, JSON.toJSONString(orderModel))
                .param(Params.TIME, LocalDateTime.now().format(formatter))
                .build();

        //4.返回前端
        return orderModel;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    String generateOrderNo() {
        //订单号有16位
        StringBuilder stringBuilder = new StringBuilder();
        //前8位为时间信息，年月日
        LocalDateTime now = LocalDateTime.now();
        String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-", "");
        stringBuilder.append(nowDate);

        //中间6位为自增序列
        //获取当前sequence
        int sequence = 0;
        Sequence sequenceDO = sequenceDOMapper.findByName("order_info");
        sequence = sequenceDO.getCurrentValue();
        sequenceDO.setCurrentValue(sequenceDO.getCurrentValue() + sequenceDO.getStep());
        sequenceDOMapper.save(sequenceDO);
        String sequenceStr = String.valueOf(sequence);
        for (int i = 0; i < 6 - sequenceStr.length(); i++) {
            stringBuilder.append(0);
        }
        stringBuilder.append(sequenceStr);


        //最后2位为分库分表位,暂时写死
        stringBuilder.append("00");

        return stringBuilder.toString();
    }

    private Order convertFromOrderModel(OrderDTO orderModel) {
        if (orderModel == null) {
            return null;
        }
        Order orderDO = new Order();
        BeanUtils.copyProperties(orderModel, orderDO);
        orderDO.setItemPrice(orderModel.getItemPrice());
        orderDO.setOrderPrice(orderModel.getOrderPrice());
        return orderDO;
    }
}
